package server;

import com.cedarsoftware.util.io.JsonReader;
import com.cedarsoftware.util.io.JsonWriter;
import shared.CompObj;
import shared.Consts;
import java.awt.Dimension;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import javax.swing.JFrame;
import java.net.*;
import java.util.concurrent.PriorityBlockingQueue;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import network.Net2QRunnable;
import network.NetQProxy;
import network.Q2NetRunnable;
import packet.CommandRequest;

/**
 * Server
 */
public class Server extends JFrame
{
  public ObjectInputStream socketIn;
  public ObjectOutputStream socketOut;
  
  JsonWriter jsonOut;
  JsonReader jsonIn;
  
  private JTextArea systemLog;
  private JScrollPane logPane;

  /**
   * Constructor
   * Initializes minimalistic logging GUI
   */
  public Server()
  {
    setTitle("InEquity Server");
    setSize(new Dimension(500, 200));
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    systemLog = new JTextArea();
    logPane = new JScrollPane(systemLog);
    systemLog.setEditable(false);
    add(logPane);
  }

  /**
   * Waits for clients to connect and returns a proxy with their connection objects
   * @param serverSocket the listening server socket
   * @param srvQ server request queue
   * @return proxy containing connection objects for single client
   */
  public NetQProxy acceptClientConnection(ServerSocket serverSocket,
          PriorityBlockingQueue<CommandRequest> srvQ)  
  {
    return acceptClientConnection(-1, serverSocket, srvQ);
  }
  
  /**
   * Waits for clients to connect and returns a proxy with their connection objects
   * @param serverSocket the listening server socket
   * @param srvQ server request queue
   * @return proxy containing connection objects for single client
   */
  public NetQProxy acceptClientConnection(int ID, ServerSocket serverSocket,
          PriorityBlockingQueue<CommandRequest> srvQ)
  {
    Socket IOSocket;
    PriorityBlockingQueue<CommandRequest> clientQ = null;
    Net2QRunnable rIn;
    Q2NetRunnable rOut;
    Thread tIn = null;
    Thread tOut = null;

    try
    {
      IOSocket = serverSocket.accept();

      socketOut = new ObjectOutputStream(IOSocket.getOutputStream());
      socketIn = new ObjectInputStream(IOSocket.getInputStream());

      jsonOut = new JsonWriter(socketOut);
      
      jsonIn = new JsonReader(socketIn);
      
      clientQ = new PriorityBlockingQueue<>(Consts.SERVER_QUEUE_SIZE, new CompObj());

      rOut = new Q2NetRunnable(ID, jsonOut, clientQ);
      rOut.enableLogging(this);

      rIn = new Net2QRunnable(ID, jsonIn, srvQ);
      rIn.setLoggingServer(this);

      tOut = new Thread(rOut);
      tIn = new Thread(rIn);

      tOut.start();
      tIn.start();

    }
    catch(IOException e)
    {
      e.printStackTrace();
    }

    return new NetQProxy(tIn, tOut, clientQ);
  }

  /**
   * Posts a log message to the gui
   * @param logMsg message to be logged
   */
  public void postLogMsg(String logMsg)
  {
    systemLog.append('\n' + logMsg);
    SwingUtilities.invokeLater(new Runnable()
    {
      @Override
      public void run()
      {
        systemLog.setCaretPosition(systemLog.getText().length());
      }
    });
  }
}
